/**
 * 克隆对象
 * obj：被克隆对象
 */
function clone<T>(obj: T): T {
  if (obj === null || typeof obj !== "object") {
    return obj;
  }
  let copyObj: any = undefined;
  if (obj instanceof Date) {
    copyObj = new Date();
    copyObj.setTime(obj.getTime());
    return copyObj;
  }
  if (obj instanceof Array) {
    copyObj = [];
    for (let i = 0; i < obj.length; i++) {
      copyObj[i] = clone(obj[i]);
    }
    return copyObj;
  }
  if (obj instanceof Object) {
    copyObj = {};
    for (let attr in obj) {
      copyObj[attr] = clone(obj[attr]);
    }
    return copyObj;
  }
  return copyObj;
}
/**
 * 生成GUID
 * showLine：是否显示线条，默认不显示
 */
const guid = (showLine?: boolean) => {
  let guid = "";
  for (let i = 1; i <= 32; i++) {
    let n = Math.floor(Math.random() * 16.0).toString(16);
    guid += n;
    if (showLine) {
      if (i === 8 || i === 12 || i === 16 || i === 20) {
        guid += "-";
      }
    }
  }
  return guid;
};
/**
 * 判断浏览器类型，PC返回true，移动端返回false
 */
const isPc = () => {
  let userAgentInfo = navigator.userAgent;
  let agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"];
  let flag = true;
  for (let v = 0; v < agents.length; v++) {
    if (userAgentInfo.indexOf(agents[v]) > 0) {
      flag = false;
      break;
    }
  }
  return flag;
};

/**
 * 存储/读取localStorage数据
 * name: localStorage的key
 * value: localStorage的value
 */
const storage = (name: string, value?: any) => {
  if (!localStorage) {
    return "";
  }
  if (value !== undefined) {
    localStorage.setItem(name, JSON.stringify(value));
  } else {
    let value = localStorage.getItem(name);
    if (value) {
      return JSON.parse(value);
    }
    return;
  }
};

/**
 * 存储/读取sessionStorage数据
 * name: localStorage的key
 * value: localStorage的value
 */
const session = (name: string, value?: any) => {
  if (!sessionStorage) {
    return;
  }
  if (value !== undefined) {
    sessionStorage.setItem(name, JSON.stringify(value));
  } else {
    let value = sessionStorage.getItem(name);
    if (value) {
      return JSON.parse(value);
    }
    return;
  }
};

/**
 * fixStylePX
 * name: px
 * value: convertPX
 */
const fixStylePX = (px: any, convertPX: Function) => {
  if (!px) {
    return;
  }
  if (px.includes("%") || px === "auto") {
    return px;
  }
  return convertPX(px.replace("px", "")) + "px";
};
/**
 * 检查地址是否可以访问
 * @param serverUrl
 */
const checkServer = (serverUrl: string, callback: Function) => {
  var img = new Image();
  var start = new Date().getTime();
  var isReturn = false;
  img.src = `${serverUrl}/image/logo.png`;
  img.onload = function () {
    isReturn = true;
    var elapsed = new Date().getTime() - start;
    console.log(`Ping：${serverUrl} ${elapsed}ms`);
    callback(true);
  };
  img.onerror = function () {
    if (!isReturn) {
      console.log(`Ping：${serverUrl} 失败`);
      callback(false);
    }
  };
  setTimeout(() => {
    if (!isReturn) {
      isReturn = true;
      console.log(`Ping：${serverUrl} 失败`);
      callback(false);
    }
  }, 200);
};
/**
 * @description: 等待结束后再执行
 * @param time 等待时间，单位毫秒
 * @return
 */
const wait = (time: number) => {
  return new Promise((resolve) => setTimeout(resolve, time));
};

/**
 * @description: 深冻结对象
 * @param object 要冻结的对象
 * @return
 */
const deepFreeze = <T extends Record<string, any>>(object: T): T => {
  // 首先冻结第一层的属性
  Object.freeze(object);

  // 对象的每个属性，如果是对象类型的话，递归地冻结
  Object.getOwnPropertyNames(object).forEach((prop) => {
    if (
      object.hasOwnProperty(prop) &&
      object[prop] !== null &&
      (typeof object[prop] === "object" || typeof object[prop] === "function") &&
      !Object.isFrozen(object[prop])
    ) {
      deepFreeze(object[prop]);
    }
  });
  return object;
};
/**
 * 将JavaScript对象转换为FormData对象，以便可以通过HTTP请求发送。
 * @param {Object} objectToConvert - 要转换的JavaScript对象。
 * @param {string} [rootName] - 在生成的FormData对象中，objectToConvert对象的属性的基础名称。
 * @param {FormData} [existingFormData] - 可选的FormData对象，如果提供，将在此对象上添加新的字段。
 * @returns {FormData} - 包含objectToConvert对象属性的FormData对象。
 */
const convertObjectToFormData = (objectToConvert: any, rootName?: string, existingFormData?: FormData) => {
  let formData = existingFormData || new FormData();
  if (rootName && isPrimitive(objectToConvert)) {
    objectToConvert && formData.append(rootName, objectToConvert);
    return formData;
  }
  for (let property in objectToConvert) {
    if (!objectToConvert.hasOwnProperty(property)) {
      continue;
    }
    let formKey = rootName ? `${rootName}[${property}]` : property;
    // 如果属性是一个File对象，直接添加到FormData
    if (objectToConvert[property] instanceof File) {
      formData.append(`${rootName}.${property}`, objectToConvert[property]);
      continue;
    }
    // 如果属性是一个数组
    if (Array.isArray(objectToConvert[property])) {
      // 如果数组中的所有元素都是File对象，直接添加到FormData
      if (objectToConvert[property].every((item: any) => item instanceof File)) {
        objectToConvert[property].forEach((item: File) => {
          formData.append(!rootName ? property : `${rootName}.${property}`, item);
        });
        continue;
      }
      // 否则，对数组中的每个元素进行递归处理
      objectToConvert[property].forEach((item: any, index: number) => {
        let arrayFormKey = `${formKey}[${index}]`;
        convertObjectToFormData(item, arrayFormKey, formData);
      });
      continue;
    }
    // 如果属性是一个对象，进行递归处理
    if (typeof objectToConvert[property] === "object") {
      convertObjectToFormData(objectToConvert[property], formKey, formData);
      continue;
    }
    // 如果属性是一个基本类型（如字符串、数字等），直接添加到FormData
    objectToConvert[property] && formData.append(formKey, objectToConvert[property]);
  }
  return formData;
};
/**
 * @description: 判断是否是原始类型
 * @param obj 对象
 * @returns
 */
const isPrimitive = (obj: any) => {
  return (typeof obj !== "object" && typeof obj !== "function") || obj === null;
};
const isJSON = (str: string) => {
  try {
    JSON.parse(str);
    return true;
  } catch (e) {
    return false;
  }
};
/**
 * @description: 获取单元格上的data-set
 * @param el 单元格元素
 * @param attr data-set名称
 * @param recursion 是否递归查找，默认不递归
 * @return
 */
const getDataSet = (el: Element, attr: string, recursion: boolean = false): string | undefined | null => {
  if (el.hasAttribute(attr)) {
    return el.getAttribute(attr);
  }
  if (recursion) {
    for (let child of el.children) {
      return getDataSet(child, attr, true);
    }
  }
  return undefined;
};

/**
 * @description: 数字转中文
 * @param num 数字
 * @return 
 */
const numberToChinese = (num: number) => {
  const units = ['', '十', '百', '千', '万', '亿'];
  const digits = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九'];
  
  if (num === 0) return digits[0]; // 特殊处理 0 的情况

  let result = '';
  let strNum = String(num);
  let len = strNum.length;

  for (let i = 0; i < len; i++) {
      const n = parseInt(strNum[i]);
      const unitIndex = len - i - 1; // 当前位的单位索引

      if (n !== 0) {
          result += digits[n] + units[unitIndex];
      } else if (i < len - 1 && strNum[i + 1] !== '0') {
          // 如果当前位是 0，并且下一位不是 0，添加 '零'
          result += digits[0];
      }
  }

  // 处理 "一十" 变为 "十"，并去掉末尾的 "零"
  result = result.replace(/^一十/, '十').replace(/零+$/, '');

  return result;
}

/**
 * @description: 类型守卫，判断Ref中的T是否非空。由于Vue的Ref包装导致TS无法自动将`Ref<T | undefined>`收缩为`Ref<T>`
 * @param T
 * @return 
 */
const isRefValid = <T>(ref: Ref<T | undefined>): ref is Ref<T> => {
  return Boolean(ref.value);
}

export default {
  clone,
  guid,
  isPc,
  storage,
  session,
  fixStylePX,
  checkServer,
  wait,
  deepFreeze,
  convertObjectToFormData,
  isJSON,
  getDataSet,
  numberToChinese,
  isRefValid
};
